package org.swift.commons.xml.vtd;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.Map;

import org.swift.commons.xml.Match;
import org.swift.commons.xml.NamespaceDefiner;

public class IndexedMatch  implements Match {
		
	private final File file;
	
	private final byte[] xml;
	
	private final long offset;
	private final int length;
	private NamespaceDefiner definer;
	
	
	public IndexedMatch(File file, long offset, int length, Map<String, String> namespaces) {
		this.file = file;
		this.xml = null;
		this.offset = offset;
		this.length = length;
		this.definer = new NamespaceDefiner(namespaces);
	}
	
	public IndexedMatch(byte[] xml, long offset, int length, Map<String, String> namespaces) {
		this.file = null;
		this.xml = xml;
		this.offset = offset;
		this.length = length;
		this.definer = new NamespaceDefiner(namespaces);
	}
	
	@Override
	public String getValue() {
		return getValue(true);
	}

	@Override
	public String getValue(boolean includeNamespace) {		
		String value;
	
		if (this.xml == null) {
			RandomAccessFile randomAccessFile = null;
			try {
				randomAccessFile = new RandomAccessFile(file, "r");		
				FileChannel channel = randomAccessFile.getChannel();		
				MappedByteBuffer buffer = channel.map(MapMode.READ_ONLY, offset, length);
				byte[] bytes = new byte[this.length];
				buffer.get(bytes);
				value = new String(bytes);				
			} catch (Exception e) {
				throw new RuntimeException(e);
			} finally {
				if (randomAccessFile != null) {
					try {
						randomAccessFile.close();
					} catch (IOException e) {						
						e.printStackTrace();
					}
				}
			}
		} else {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
	        out.write(this.xml, (int)this.offset, this.length);			        
	        value = new String(out.toByteArray());			
		}
		if (includeNamespace) {
			return definer.defineNamespaces(value);
		} else {
			return value;
		}
	}
	


	@Override
	public int getLength() {
		return this.length;
	}

	@Override
	public int getPosition() {
		return (int)this.offset;
	}

	@Override
	public boolean isIndexed() {
		return true;
	}
	
}
